/*
 * Board.hpp
 *
//l:
//0            00
//1          01  02
//2        03  04  05
//3      06  07  08  09
//4    10  11  12  13  14
// c:00  01  02  03  04
 *
//Rotation 60 CW
//l:
//0            10
//1          11  06
//2        12  07  03
//3      13  08  04  01
//4    14  09  05  02  00
// c:00  01  02  03  04
*
//Rotation 120 CW
//l:
//0            14
//1          09  13
//2        05  08  12
//3      02  04  07  11
//4    00  01  03  06  10
// c:00  01  02  03  04
 *
 // 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
 *
 *  Created on: 10 déc. 2011
 *      Author: Elca
 */

#ifndef BOARD_HPP_
#define BOARD_HPP_

#include "def.hpp"
#include "HolePosition.hpp"
#include "HoleJump.hpp"
#include <iostream>
#include <vector>
#include <map>

using namespace std;

namespace pcm {

class BoardInfos {
public:

	//Construtor number
	static LL cons;

	BoardInfos();

	inline BoardInfos(const BoardInfos* _boardInfos){
		//cons++;
		m_board = _boardInfos->m_board;
		m_numberJoin = _boardInfos->m_numberJoin;
		m_numberPeg = _boardInfos->m_numberPeg;
	}
	virtual ~BoardInfos();

	inline static int gameSize() {
		return m_gameSize;
	}
	inline static int gameNumberHole() {
		return m_gameNumberHole;
	}
	inline static const HolePosition& holePosition(short int hole) {
		return m_holePosition[hole];
	}
	inline static const vector<HoleJump>& startHoleJumps(short int hole) {
		return m_startHoleJumps[hole];
	}
	inline static const vector<HoleJump>& endlHoleJumps(short int hole) {
		return m_endHoleJumps[hole];
	}

//	inline static BoardInfos* getNextRotation(){
//		BoardInfos* nextBoard = new BoardInfos(this);
//
//	}
	inline bool hole(short int _holeToGet) const{
		return (m_board>>_holeToGet)&1;
	}
	inline bool hole(short int _lignToGet,short int _colToGet) const{
		return hole(HolePosition::convToHoleNumber(_lignToGet,_colToGet));
	}
	inline void setHole(short int holeToSet, bool setPeg){
		LL mask = (LL)1<<holeToSet;
		if(setPeg){
			m_board |=mask ;
		}else{
			m_board &= ~mask;
		}
	}
	inline LL* boardPointer(){
		return &m_board;
	}
	inline LL board() const{
		return m_board;
	}
	inline short int numberPeg() const {
		return m_numberPeg;
	}
	inline void decrementNumberPeg(){
		m_numberPeg -=1;
	}
	inline LL numberJoin() const {
		return m_numberJoin;
	}
	inline void incrementNumberJoin(LL _increment=1){
		m_numberJoin+=_increment;
	}

	inline BoardInfos* applyMove(HoleJump move){
		BoardInfos* board = new BoardInfos(this);
		board->setHole(move.start(),false);
		board->setHole(move.jump(),false);
		board->setHole(move.end(),true);
		board->decrementNumberPeg();
		return board;
	}

	inline BoardInfos applyMoveStack(HoleJump move){
		BoardInfos board(this);
		board.setHole(move.start(),false);
		board.setHole(move.jump(),false);
		board.setHole(move.end(),true);
		board.decrementNumberPeg();
		return board;
	}
	static void updateGameInfos(short int gameSize);

	void initBoard(short int holeToRemove);
	void fillBoard();
	void calculateHolesPos();
	void calculateHolesJumps();

	void printBoard() const;
	void printJumps() const;
	void printHolePos() const;


protected:
	static short int m_gameNumberHole;
	static short int m_gameSize;
	static HolePosition *m_holePosition;
	static vector<HoleJump> *m_startHoleJumps;
	static vector<HoleJump> *m_endHoleJumps;

	LL m_board;
	short int m_numberPeg;
	LL  m_numberJoin;

	inline static  void setGameNumberHole(short int gameSize){
		m_gameNumberHole = (gameSize+1)*(gameSize/2.0);
	}

	inline static void setGameSize(short int gameSize){
		BoardInfos::m_gameSize = gameSize;
	}
private:
};

} /* namespace pcm */
#endif /* BOARD_HPP_ */
